package com.duguyuan.server;

import com.duguyuan.entity.User;
import com.duguyuan.service.ProxyUserService;
import com.duguyuan.service.UserService;
import com.duguyuan.utils.EnhancedHashMap;
import com.duguyuan.utils.MessageProtocol;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerService {

    static String ipAddress = MessageProtocol.DEFAULT_SERVER_IP_ADDRESS;
    static int serverPort = MessageProtocol.DEFAULT_SERVER_PORT;

    private UserService userService;

    private ServerFrame serverFrame;

    static EnhancedHashMap<String, Socket> clients = new EnhancedHashMap<String, Socket>();
    static int onlineUserCount = 0; // 在线人数
    boolean serverIsStarted;

    public ServerService(ServerFrame serverFrame) {
        this.serverFrame = serverFrame;
        userService = ProxyUserService.getProxyUserService();
    }

    /**
     * 启动服务器执行的方法
     */
    public void openServer() {
        ServerSocket listener = null;
        try {
            listener = new ServerSocket(serverPort, 0, InetAddress.getByName(ipAddress));
            serverFrame.logTextArea.append("服务器启动成功.....\n");
            serverFrame.ipTextField.setEditable(false);
            serverFrame.portTextField.setEditable(false);
            while(true) {
                Socket socket = listener.accept();
                new ServerThread(socket).start();
            }
        } catch (IOException e) {
            serverFrame.logTextArea.append("服务器启动失败.....\n");
            e.printStackTrace();
        } finally {
            try {
                if (listener != null) {
                    listener.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.exit(0);
        }
    }

    public void addObserver(String username, Socket socket) {
        clients.put(username, socket);
    }

    public void deleteObserver(String username) {
        clients.remove(username);
    }

    public void notifyObservers(String message, String type) {
        try {
            for (Socket clientSocket : ServerService.clients.valueSet()) {
                sendMessage(clientSocket, type + message + type);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage(Socket socket, String line) throws IOException {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
        bw.write(line);
        bw.newLine();
        bw.flush();
    }

    class ServerThread extends Thread {

        private String username;
        private Socket socket;
        private String ipAddress;

        public ServerThread(Socket socket) {
            this.socket = socket;
            ipAddress = socket.getInetAddress() + ":" + socket.getPort();
        }

        public void synchronizeUsers() {

            try {
                for (String name : clients.keySet()) {
                    sendMessage(socket, MessageProtocol.ADD_USER + name + MessageProtocol.ADD_USER);
                }
                addObserver(this.username, socket);
                notifyObservers(this.username, MessageProtocol.ADD_USER);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {

            BufferedReader bufferedReader = null;
            BufferedWriter bufferedWriter = null;
            try {
                // 获取Socket对应的输入流
                bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
                // 获取Socket对应的输出流
                bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
                String line = null;
                while((line = bufferedReader.readLine()) != null) {
                    if (line.startsWith(MessageProtocol.REGISTER_ROUND) && line.endsWith(MessageProtocol.REGISTER_ROUND)) { // 注册
                        String realMessage = getRealMessage(line);
                        String username = realMessage.split(MessageProtocol.SEPARATOR)[0];
                        String password = realMessage.split(MessageProtocol.SEPARATOR)[1];
                        if (userService.register(new User(username, password)) == 1) {
                            // 注册成功
                            sendMessage(socket, MessageProtocol.REGISTER_SUCCESS);
                        } else {
                            // 用户名已存在
                            sendMessage(socket, MessageProtocol.REGISTER_ERROR);
                        }
                    } else if (line.startsWith(MessageProtocol.LOGIN_ROUND) && line.endsWith(MessageProtocol.LOGIN_ROUND)) { // 登录
                        String realMessage = getRealMessage(line);
                        String username = realMessage.split(MessageProtocol.SEPARATOR)[0];
                        String password = realMessage.split(MessageProtocol.SEPARATOR)[1];
                        if (userService.login(username, password) == null) {
                            // 用户名或密码错误
                            sendMessage(socket, MessageProtocol.LOGIN_ERROR);
                        } else {
                            if (ServerService.clients.containsKey(username)) {
                                // 账号已在线
                                sendMessage(socket, MessageProtocol.LOGIN_ONLINE);
                            } else {
                                // 登录操作
                                this.username = username;
                                sendMessage(socket, MessageProtocol.LOGIN_SUCCESS);
                                // 用户上线操作
                                serverFrame.logTextArea.append("【" + this.username + "】用户已上线......\n");
                                serverFrame.onlineUsersTextField.setText((++onlineUserCount) + "");
                                serverFrame.usersListModel.addElement(this.username + " [" + ipAddress.substring(1) + "]");
                            }
                        }
                    } else if(line.startsWith(MessageProtocol.SYN_USER) && line.endsWith(MessageProtocol.SYN_USER)) {
                        synchronizeUsers();
                    } else if (line.startsWith(MessageProtocol.PRIVATE_ROUND) && line.endsWith(MessageProtocol.PRIVATE_ROUND)) { // 私聊
                        String realMessage = getRealMessage(line);
                        String username = realMessage.split(MessageProtocol.SEPARATOR)[0];
                        String message = realMessage.split(MessageProtocol.SEPARATOR)[1];
                        Socket privateSocket = ServerService.clients.get(username);
                        sendMessage(privateSocket, MessageProtocol.PRIVATE_ROUND + this.username + MessageProtocol.SEPARATOR + message + MessageProtocol.PRIVATE_ROUND);
                        serverFrame.logTextArea.append("私聊 ===>> " + "【" + this.username + "】对【" + username + "】说: " + message + "\n");
                    } else if (line.startsWith(MessageProtocol.PUBLIC_ROUND) && line.endsWith(MessageProtocol.PUBLIC_ROUND)) { // 群聊
                        String message = getRealMessage(line);
                        message = "【" + this.username + "】发言: " + message;
                        notifyObservers(message, MessageProtocol.PUBLIC_ROUND);
                        serverFrame.logTextArea.append("群聊 ===>> " + message + "\n");
                    }
                }
            } catch (IOException e) {
                //e.printStackTrace();
                // 用户下线操作
                if (username != null) {
                    serverFrame.logTextArea.append("【" + username + "】用户已下线......\n");
                    deleteObserver(username);
                    notifyObservers(username, MessageProtocol.DELETE_USER);
                    serverFrame.onlineUsersTextField.setText((--onlineUserCount) + "");
                    serverFrame.usersListModel.removeElement(username + " [" + ipAddress.substring(1) + "]");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (bufferedReader != null) {
                        bufferedReader.close();
                    }
                    if (bufferedWriter != null) {
                        bufferedWriter.close();
                    }
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 将读到的内容去掉前后的协议字符，恢复成真实数据
         * @param line
         * @return
         */
        public String getRealMessage(String line) {
            return line.substring(MessageProtocol.PROTOCOL_LENGTH, line.length() - MessageProtocol.PROTOCOL_LENGTH);
        }
    }

}